package edu.vt.ece.rt.benchmark.bank;

import java.util.Random;

import edu.vt.ece.rt.quorum.ClustersManager;
import edu.vt.ece.rt.quorum.Resource;
import edu.vt.ece.rt.util.Logger.Logger;



public class Benchmark extends edu.vt.ece.rt.benchmark.Benchmark{

	final int amount = 10000;
	final int transfer = 10;
	private Random random = new Random(hashCode());
	
	@Override
	protected void createLocalObjects() {
		Integer id = ClustersManager.baseClusterId;
		int nodes = ClustersManager.nodesCount();
		try {
			Thread.sleep(1000+800*id);		//Different timings for all nodes
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		Logger.debug("Uploading " + localObjectsCount + " objects over " + nodes + " nodes quorum.");
		for(int i=0; i<localObjectsCount; i++){
			if((i % nodes)== id){
				Logger.debug("Created quorum object " + i+ " on node "+id);
				try {
					Logger.debug(">");
					new BankAccount(id + "-" + i, amount);
				} catch (Throwable e) {
					e.printStackTrace();
				}
			}
		}
		//Add some wait to make sure objects are created successfully
		try {
			Thread.sleep(800*(nodes-id-1)+1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	@Override
	protected int getOperandsCount() {	return 2; }

	@Override
	protected Object randomId() {
		int obj = random.nextInt(localObjectsCount);
		return (obj%ClustersManager.nodesCount()) + "-" + obj ;
	}

	@Override
	protected void readOperation(Object... ids) {
		try {
			BankAccount.totalBalance(String.valueOf(ids[0]), String.valueOf(ids[1]));
		} catch (Throwable e) {
			e.printStackTrace();
		} 
	}

	@Override
	protected void writeOperation(Object... ids) {
		try {
			BankAccount.transfer(String.valueOf(ids[0]), String.valueOf(ids[1]), transfer);
		} catch (Throwable e) {
			e.printStackTrace();
		} 
	}

	@Override
	protected String getLabel() {
		return "Bank-QR";
	}


	@Override
	protected void checkSanity() {
		if (ClustersManager.baseClusterId != 0) {
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return;
		}
		try {
			Logger.debug("Going to Sleep before Sanity Check");
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		long balance = 0;
		int node = ClustersManager.nodesCount();
		for(int i=0; i<localObjectsCount; i++){
			for(int j=0;j<node;j++){
				if(i%node==j){
					try {
						long b=((BankAccount) Resource.getQObject(j + "-" + i)).checkBalance();
						System.out.println(j+"-"+i+ " amount " + b); 
						balance +=b;
					} catch (Throwable e) {
						e.printStackTrace();
					}	
				}
			}
		}
		if(balance==localObjectsCount*amount){
			System.out.println("Passed sanity check");
		}
		else
			System.out.println("Failed sanity check."+
					"\nbalance = "+ balance+
					"\nexpected = "+localObjectsCount*amount);

	}	
}

